package cn.itcast.nems.product.scheduler;

import cn.itcast.nems.product.dao.dataobject.BizNo;
import cn.itcast.nems.product.dao.dataobject.ProductDO;
import cn.itcast.nems.product.dao.dataobject.TuitionFeeDO;
import cn.itcast.nems.product.dao.dataobject.TuitionFeePhaseDO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @author liyong
 * create: 2023-09-04 13:45:02
 **/
public class ProductPriceCal {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    protected final List<ProductDO> products;
    protected final List<TuitionFeeDO> tuitionFees;
    // key: tuitionFeeId
    protected final Map<Integer, List<TuitionFeePhaseDO>> phases;
    // key: tuitionFeeId
    protected final Map<Integer, Set<String>> schools;
    // key: clazzId, value: phaseCount
    protected final Map<Integer, Integer> clazzPhaseCounts;

    public ProductPriceCal(List<ProductDO> products,
                           List<TuitionFeeDO> tuitionFees,
                           Map<Integer, List<TuitionFeePhaseDO>> phases,
                           Map<Integer, Set<String>> schools) {
        this.products = products;
        this.tuitionFees = tuitionFees;
        this.phases = phases;
        this.schools = schools;
        this.clazzPhaseCounts = new HashMap<>();
        for (ProductDO product : products) {
            BizNo bizNo = new BizNo(product.getBizNo());
            clazzPhaseCounts.compute(bizNo.getClazzId(), (key, oldValue) -> {
                if (oldValue == null) {
                    return bizNo.getPhase();
                }
                return bizNo.getPhase() > oldValue ? bizNo.getPhase() : oldValue;
            });
        }
    }

    /**
     * 查找阶段学费配置
     *
     * @param product    产品
     * @param phaseCount 阶段数量
     * @param useDate    配置的使用日期
     * @return 阶段学费配置
     */
    protected TuitionFeePhaseDO findTuitionFeePhase(ProductDO product,
                                                    int phaseCount,
                                                    LocalDate useDate) {
        TuitionFeeDO tuitionFee = this.findTuitionFee(product, phaseCount, useDate);
        TuitionFeePhaseDO result = null;
        if (tuitionFee != null) {
            final List<TuitionFeePhaseDO> tuitionFeePhases = phases.get(tuitionFee.getId());
            if (tuitionFeePhases != null) {
                BizNo bizNo = product.getBizNoObject();
                result = tuitionFeePhases.stream().filter(p -> p.getPhaseNumber().equals(String.valueOf(bizNo.getPhase()))).findAny().orElse(null);
            }
        }
        return result;
    }

    /**
     * 查找学费配置，不考虑使用日期条件（可以查找时间维度）
     *
     * @param product    产品
     * @param phaseCount 阶段数量
     * @return 班级学费配置
     */
    protected TuitionFeeDO findTuitionFee(ProductDO product, int phaseCount) {
        return this.findTuitionFee(product, phaseCount, null);
    }

    protected TuitionFeeDO findTuitionFee(ProductDO product, int phaseCount, LocalDate useDate) {
        TuitionFeeDO result = null;
        for (TuitionFeeDO fee : tuitionFees) {
            if (this.productMatchTuitionFee(product, fee, phaseCount)) {
                if (useDate != null) {
                    final LocalDate startDate = fee.getStartDate();
                    final LocalDate endDate = fee.getEndDate();
                    if (startDate != null && endDate != null) {
                        if (useDate.compareTo(startDate) >= 0 && useDate.compareTo(endDate) <= 0) {
                            result = fee;
                            break;
                        }
                    } else {
                        if (fee.getUseDate().compareTo(useDate) <= 0) {
                            result = fee;
                            break;
                        }
                    }
                } else {
                    result = fee;
                    break;
                }
            }
        }
        return result;
    }

    protected boolean productMatchTuitionFee(ProductDO product, TuitionFeeDO fee, int phaseCount) {
        final Set<String> schoolIds = schools.get(fee.getId());
        return fee.getClassTypeId().equals(product.getClassTypeId())
                && this.phaseNumberMatch(phaseCount, fee.getPhaseNumber())
                && schoolIds != null
                && schoolIds.contains(product.getCampusId());
    }

    protected boolean phaseNumberMatch(int phaseCount, String phaseNumber) {
        if (String.valueOf(phaseCount).equals(phaseNumber)) {
            return true;
        }
        if (phaseCount == 1) {
            if (!StringUtils.hasText(phaseNumber)) {
                return true;
            }
        }
        return false;
    }
}
